#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <stdio.h>
#include <stdlib.h>

#include "caevent.h"

#include "catimer.h"


/*
catimer_t* alloc_catimer(es_t *psys)
{
	catimer_t* ptimer;
	ptimer = (catimer_t*)malloc(sizeof(catimer_t));
	if(ptimer)
	{
		memset(ptimer, 0, sizeof(catimer_t));
		psys->timer_alloc_cnt++;
		ptimer->psys = psys;
		return ptimer;
	}
	else
		return NULL;
}

void free_catimer(catimer_t* ptimer)
{
	ptimer->psys->timer_alloc_cnt--;
	free(ptimer);
}
*/

void timer_event_cb(evt_t* pevt, int fd, int events)
{
	uint64_t buf;
	catimer_t* ptimer = (catimer_t*)pevt->user;
	read(fd, &buf, sizeof(buf));
	//printf("timer exp, %lu, %ld \n", buf, sizeof(buf));
	ptimer->timercb(ptimer, ptimer->user);
}

catimer_t* catimer_open(es_t* psys, catimer_t* ptimer, unsigned int msec, TIMERCB cb,  void* user)
{
	#if 0
	catimer_t* ptimer;
	ptimer = alloc_catimer(psys);
	#endif

#ifndef ANDROID
	ptimer->fd = timerfd_create(CLOCK_MONOTONIC, TFD_NONBLOCK|TFD_CLOEXEC);
#else
	ptimer->fd = timerfd_create(0, 0);
	setNonBlockMode(ptimer->fd);
#endif
	//printf("timer fd = %d\n", ptimer->fd);
	
	ptimer->psys = psys;	
	ptimer->timercb = cb;
	ptimer->user = user;

	catimer_set(ptimer, msec);
	
	ptimer->pevt = es_reg(psys, ptimer->fd, EPOLLIN, timer_event_cb, ptimer);
	return ptimer;	
}


void catimer_close(catimer_t* ptimer)
{
	if(ptimer->fd==0)
		return;
	close(ptimer->fd);

	if(ptimer->pevt)
		es_dereg(ptimer->psys, ptimer->pevt);
	ptimer->pevt = NULL;	
	ptimer->fd = 0;
	#if 0
	free_catimer(ptimer);
	#endif
}


void catimer_set(catimer_t* ptimer, unsigned int msec)
{
	ptimer->msec = msec;
	
	struct itimerspec newtm;

	newtm.it_interval.tv_sec = msec/1000;
	newtm.it_interval.tv_nsec = (msec % 1000)*1000*1000;
	newtm.it_value.tv_sec = msec/1000;
	newtm.it_value.tv_nsec = newtm.it_interval.tv_nsec;


	int ret = timerfd_settime(ptimer->fd, 0, &newtm, NULL);
	//printf("settimer ret=%d \n", ret);
	//ptimer->pevt = es_reg(psys, ptimer->fd, EPOLLIN, timer_event_cb, ptimer);

}

void catimer_reset(catimer_t* ptimer)
{
	catimer_set(ptimer, ptimer->msec);
}




static estimer_t* find_estimer(es_t* psys, int tid)
{
	lklist* ptimer;
	if(psys->timer_list==NULL)
		return NULL;
	for(ptimer=psys->timer_list;ptimer;)
	{
		if(ptimer->udata==tid)
			return (estimer_t*)ptimer;
		ptimer=ptimer->next;
		if(ptimer==psys->timer_list)
			break;
	}
	return NULL;
}


static estimer_t* alloc_estimer(es_t* psys, unsigned int tid)
{
	estimer_t* ptimer;
	ptimer = (estimer_t*)malloc(sizeof(estimer_t));
	psys->timer_cnt++;
	ptimer->list.udata = tid;
	
	if(psys->timer_list) {
		lkadd(psys->timer_list, &ptimer->list);
	}
	else
	{
		psys->timer_list = &ptimer->list;
		lkinit(&ptimer->list);
	}
	return ptimer;	
}


static void free_estimer(es_t* psys, estimer_t* ptimer)
{
	if(psys->timer_list && ptimer->list.seed)
		psys->timer_cnt--;
		
	psys->timer_list = lkpop_head(&ptimer->list);
}

void free_estimer_all(es_t* psys)
{
	estimer_t* ptimer;
	if(psys->timer_list)
	{
		do {
			ptimer = (estimer_t*)lkpop_tail(psys->timer_list);
			if(!ptimer)
				break;
			catimer_close(&ptimer->t);
			free(ptimer);
			psys->timer_cnt--;
		} while(1);
	}
}

static void estimer_cb(catimer_t* pcatimer, void* user)
{
	estimer_t* pestimer = (estimer_t*)user;
	pcatimer->psys->msg_proc(pcatimer->psys, EM_TIMER, pestimer->list.udata, 0);	
}



int es_set_timer(es_t* psys, int tid, unsigned int msec, TIMERCB cb)
{
	estimer_t* ptimer;
	TIMERCB timercb;

	if(cb)
		timercb = cb;
	else
		timercb = estimer_cb;

	ptimer = find_estimer(psys, tid);
	if(!ptimer)
	{
		ptimer = alloc_estimer(psys, tid);
		catimer_open(psys, &ptimer->t, msec, timercb, ptimer);
	}
	else
		catimer_set(&ptimer->t, msec);

	return 0;	
}

void es_kill_timer(es_t* psys, int tid)
{
	estimer_t* ptimer = find_estimer(psys, tid);
	if(ptimer)
	{
		catimer_close(&ptimer->t);
		free_estimer(psys, ptimer);
	}
}
